* { box-sizing: border-box; margin: 0; padding: 0; }
/* Hidden-field helper for demo mode */
.hidden-field { display: none !important; }
:root {
--primary: #ff6b35;
--primary-dark: #e55a2b;
--dark: #1a1a2e;
--light: #f8f9fa;
--gray: #6c757d;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background: var(--dark);
color: white;
min-height: 100vh;
}
.header {
background: rgba(0,0,0,0.3);
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.logo { font-size: 1.5rem; font-weight: bold; color: var(--primary); }
.container {
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
display: grid;
grid-template-columns: 350px 1fr;
gap: 2rem;
}
.controls {
background: rgba(255,255,255,0.05);
border-radius: 12px;
padding: 1.5rem;
height: fit-content;
}
.controls h2 {
color: var(--primary);
margin-bottom: 1.5rem;
font-size: 1.2rem;
}
.form-group { margin-bottom: 1.2rem; }
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-size: 0.85rem;
color: rgba(255,255,255,0.7);
}
.form-group input,
.form-group select {
width: 100%;
padding: 0.7rem;
border: 1px solid rgba(255,255,255,0.2);
border-radius: 6px;
background: rgba(255,255,255,0.1);
color: white;
font-size: 0.95rem;
}
.form-group select option {
background: #1a1a2e;
color: white;
}
.form-group input::placeholder {
color: rgba(255,255,255,0.4);
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: var(--primary);
}
.theme-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
}
.theme-option {
padding: 0.6rem;
border: 2px solid transparent;
border-radius: 8px;
cursor: pointer;
text-align: center;
font-size: 0.8rem;
transition: all 0.2s;
}
.theme-option:hover { transform: scale(1.02); }
.theme-option.selected {
border-color: var(--primary);
background: rgba(255,107,53,0.2);
}
.theme-1 { background: linear-gradient(135deg, #1a1a2e, #ff6b35); }
.theme-2 { background: linear-gradient(135deg, #ffffff, #3498db); color: #333; }
.theme-3 { background: linear-gradient(135deg, #ff6b35, #27ae60); }
.theme-4 { background: linear-gradient(135deg, #1a1a2e, #ffd700); }
.theme-5 { background: linear-gradient(135deg, #e74c3c, #f39c12); }
.preview-frame {
background: white;
border-radius: 12px;
overflow: hidden;
min-height: 600px;
position: relative;
}
.preview-header {
background: #f0f0f0;
padding: 0.5rem 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid #ddd;
}
.preview-dot { width: 12px; height: 12px; border-radius: 50%; }
.dot-red { background: #ff5f56; }
.dot-yellow { background: #ffbd2e; }
.dot-green { background: #27c93f; }
.preview-url {
background: white;
flex: 1;
padding: 0.4rem 0.8rem;
border-radius: 4px;
font-size: 0.8rem;
color: #666;
margin-left: 1rem;
}
.preview-content {
height: calc(100% - 40px);
overflow: auto;
}
.preview-content iframe {
width: 100%;
height: 100%;
border: none;
}
.actions {
margin-top: 1.5rem;
display: flex;
gap: 1rem;
}
.btn {
flex: 1;
padding: 0.8rem 1rem;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
font-size: 0.95rem;
transition: all 0.2s;
}
.btn-primary {
background: var(--primary);
color: white;
}
.btn-primary:hover {
background: var(--primary-dark);
}
.btn-secondary {
background: rgba(255,255,255,0.1);
color: white;
}
.btn-secondary:hover {
background: rgba(255,255,255,0.2);
}
.success-message {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--dark);
border: 2px solid var(--primary);
border-radius: 12px;
padding: 2rem;
text-align: center;
z-index: 1000;
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.success-message.show { display: block; }
.success-message h3 { color: var(--primary); margin-bottom: 1rem; }
.success-message p { margin-bottom: 1rem; color: rgba(255,255,255,0.7); }
.overlay {
display: none;
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.7);
z-index: 999;
}
.overlay.show { display: block; }
.image-preview {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
margin-top: 1rem;
padding: 0.75rem;
background: rgba(0,0,0,0.2);
border-radius: 8px;
}
.image-preview img {
width: 100%;
height: 60px;
object-fit: cover;
border-radius: 4px;
}
.image-preview-label {
font-size: 0.75rem;
color: rgba(255,255,255,0.5);
margin-bottom: 0.25rem;
}
@media (max-width: 900px) {
.container { grid-template-columns: 1fr; }
.preview-frame { min-height: 400px; }
}
Page loading...
✅ Website Saved!
Your design has been saved. We'll build your custom website and contact you within 24 hours.
let selectedTheme = 'theme-1';
// Fetch custom images from Airtable (fully automated)
async function getCustomImages() {
try {
const response = await fetch('https://atlas-automation.co/api/custom-images');
if (response.ok) {
return await response.json();
}
} catch(e) {}
return {};
}
// AUTO-LOAD CUSTOM IMAGES FROM AIRTABLE
const AIRTABLE_API = "/api/airtable";
async function loadCustomImages() {
try {
const resp = await fetch("/api/airtable?table=tblrjkZ7ZLBjR0Ntb?maxRecords=100", {
headers: { "Content-Type": "application/json" }
});
const data = await resp.json();
const custom = {};
for (const record of data.records) {
const f = record.fields;
if (f["Service Type"] && f["Image Slot"] && f["Image URL"]) {
const svc = f["Service Type"];
const slot = f["Image Slot"];
if (!custom[svc]) custom[svc] = { hero: "", services: ["", "", "", "", ""] };
if (slot === "hero") custom[svc].hero = f["Image URL"];
else {
const idx = parseInt(slot.replace("service", "")) - 1;
if (idx >= 0 && idx < 5) custom[svc].services[idx] = f["Image URL"];
}
}
}
// Merge with stockImages - custom overwrites default
for (const svc of Object.keys(custom)) {
if (custom[svc].hero) stockImages[svc].hero = custom[svc].hero;
for (let i = 0; i < 5; i++) {
if (custom[svc].services[i]) stockImages[svc].services[i] = custom[svc].services[i];
}
}
console.log("Custom images loaded from Airtable");
} catch(e) {
console.log("Using default images:", e.message);
}
}
// Load custom images on startup
loadCustomImages();
// Stock images for each service type
const stockImages = {
plumbing: {
hero: "https://images.unsplash.com/photo-1585704032915-c3400ca199e7?w=1200",
services: [
"https://i.ibb.co/Q7VTfCf7/Plumber-service-1-fixing-a-leaking-pipe.png",
"https://i.ibb.co/JwMwr4m5/Plumber-service-2-cleaning-drain.png",
"https://i.ibb.co/hRKrM0Xr/Plumber-service-3-water-heater-install.png",
"https://i.ibb.co/bRWN80Fk/plumber-service-4-installing-PVC-pipe.png",
"https://i.ibb.co/FkzcL06F/Plumber-service-5-working-on-bathroom-remodel.png"
]
},
hvac: {
hero: "https://images.unsplash.com/photo-1631545806609-48e6335a4c2c?w=1200",
services: [
"https://images.unsplash.com/photo-1631545806609-48e6335a4c2c?w=400",
"https://images.unsplash.com/photo-1621905251189-08b45d6a269e?w=400",
"https://images.unsplash.com/photo-1585771724684-38269d6639fd?w=400",
"https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=400",
"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400"
]
},
roofing: {
hero: "https://images.unsplash.com/photo-1632832482219-a1a5edc9f08d?w=1200",
services: [
"https://images.unsplash.com/photo-1632832482219-a1a5edc9f08d?w=400",
"https://images.unsplash.com/photo-1605116683261-ec156b0f2d5f?w=400",
"https://images.unsplash.com/photo-1600585152220-90363fe7e115?w=400",
"https://images.unsplash.com/photo-1628069770292-4838b2b9fd8d?w=400",
"https://images.unsplash.com/photo-1600566752355-35792bedcfea?w=400"
]
},
electrical: {
hero: "https://images.unsplash.com/photo-1621905251189-08b45d6a269e?w=1200",
services: [
"https://images.unsplash.com/photo-1621905251189-08b45d6a269e?w=400",
"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400",
"https://images.unsplash.com/photo-1498050108023-c5249f4df085?w=400",
"https://images.unsplash.com/photo-1508514177221-188b1cf2f26f?w=400",
"https://images.unsplash.com/photo-1523784321324-09bf1b370e5c?w=400"
]
},
pool: {
hero: "https://images.unsplash.com/photo-1576013551627-0cc20b96c2a7?w=1200",
services: [
"https://images.unsplash.com/photo-1576013551627-0cc20b96c2a7?w=400",
"https://images.unsplash.com/photo-1576013551627-0cc20b96c2a7?w=400",
"https://images.unsplash.com/photo-1576013551627-0cc20b96c2a7?w=400",
"https://images.unsplash.com/photo-1576013551627-0cc20b96c2a7?w=400",
"https://images.unsplash.com/photo-1576013551627-0cc20b96c2a7?w=400"
]
},
painting: {
hero: "https://images.unsplash.com/photo-1562259949-e8e7689d7828?w=1200",
services: [
"https://images.unsplash.com/photo-1562259949-e8e7689d7828?w=400",
"https://images.unsplash.com/photo-1589939705384-5185137a7f0f?w=400",
"https://images.unsplash.com/photo-1562259949-e8e7689d7828?w=400",
"https://images.unsplash.com/photo-1524758631624-e2822e304c36?w=400",
"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400"
]
},
flooring: {
hero: "https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1200",
services: [
"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400",
"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400",
"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400",
"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400",
"https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400"
]
},
appliance: {
hero: "https://images.unsplash.com/photo-1558618047-f4b511d88421?w=1200",
services: [
"https://images.unsplash.com/photo-1558618047-f4b511d88421?w=400",
"https://images.unsplash.com/photo-1558618047-f4b511d88421?w=400",
"https://images.unsplash.com/photo-1558618047-f4b511d88421?w=400",
"https://images.unsplash.com/photo-1558618047-f4b511d88421?w=400",
"https://images.unsplash.com/photo-1558618047-f4b511d88421?w=400"
]
},
pest: {
hero: "https://images.unsplash.com/photo-1585771724684-38269d6639fd?w=1200",
services: [
"https://images.unsplash.com/photo-1585771724684-38269d6639fd?w=400",
"https://images.unsplash.com/photo-1585771724684-38269d6639fd?w=400",
"https://images.unsplash.com/photo-1585771724684-38269d6639fd?w=400",
"https://images.unsplash.com/photo-1585771724684-38269d6639fd?w=400",
"https://images.unsplash.com/photo-1585771724684-38269d6639fd?w=400"
]
},
siding: {
hero: "https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=1200",
services: [
"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400",
"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400",
"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400",
"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400",
"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400"
]
},
masonry: {
hero: "https://images.unsplash.com/photo-1600566752355-35792bedcfea?w=1200",
services: [
"https://images.unsplash.com/photo-1600566752355-35792bedcfea?w=400",
"https://images.unsplash.com/photo-1600566752355-35792bedcfea?w=400",
"https://images.unsplash.com/photo-1600566752355-35792bedcfea?w=400",
"https://images.unsplash.com/photo-1600566752355-35792bedcfea?w=400",
"https://images.unsplash.com/photo-1600566752355-35792bedcfea?w=400"
]
},
landscaping: {
hero: "https://images.unsplash.com/photo-1558904541-fa88e93a6f97?w=1200",
services: [
"https://images.unsplash.com/photo-1558904541-fa88e93a6f97?w=400",
"https://images.unsplash.com/photo-1598902108854-10e335adac99?w=400",
"https://images.unsplash.com/photo-1558618047-f4b511d88421?w=400",
"https://images.unsplash.com/photo-1585320806297-9794b3e4eeae?w=400",
"https://images.unsplash.com/photo-1605116683261-ec156b0f2d5f?w=400"
]
},
handyman: {
hero: "https://images.unsplash.com/photo-1581578731548-c64695ccb2ab?w=1200",
services: [
"https://images.unsplash.com/photo-1581578731548-c64695ccb2ab?w=400",
"https://images.unsplash.com/photo-1581578731548-c64695ccb2ab?w=400",
"https://images.unsplash.com/photo-1581578731548-c64695ccb2ab?w=400",
"https://images.unsplash.com/photo-1581578731548-c64695ccb2ab?w=400",
"https://images.unsplash.com/photo-1581578731548-c64695ccb2ab?w=400"
]
},
cleaning: {
hero: "https://images.unsplash.com/photo-1589939705384-5185137a7f0f?w=1200",
services: [
"https://images.unsplash.com/photo-1589939705384-5185137a7f0f?w=400",
"https://images.unsplash.com/photo-1589939705384-5185137a7f0f?w=400",
"https://images.unsplash.com/photo-1589939705384-5185137a7f0f?w=400",
"https://images.unsplash.com/photo-1589939705384-5185137a7f0f?w=400",
"https://images.unsplash.com/photo-1589939705384-5185137a7f0f?w=400"
]
},
carpet: {
hero: "https://images.unsplash.com/photo-1524758631624-e2822e304c36?w=1200",
services: [
"https://images.unsplash.com/photo-1524758631624-e2822e304c36?w=400",
"https://images.unsplash.com/photo-1524758631624-e2822e304c36?w=400",
"https://images.unsplash.com/photo-1524758631624-e2822e304c36?w=400",
"https://images.unsplash.com/photo-1524758631624-e2822e304c36?w=400",
"https://images.unsplash.com/photo-1524758631624-e2822e304c36?w=400"
]
}
};
// Theme configs
const themes = {
'theme-1': {
name: 'Bold Modern',
bg: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)',
accent: '#ff6b35',
text: '#ffffff',
secondary: '#0f3460'
},
'theme-2': {
name: 'Clean Professional',
bg: 'linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%)',
accent: '#3498db',
text: '#2c3e50',
secondary: '#ecf0f1'
},
'theme-3': {
name: 'Vibrant Service',
bg: 'linear-gradient(135deg, #fff 0%, #fff5e6 100%)',
accent: '#ff6b35',
text: '#333333',
secondary: '#e8f5e9'
},
'theme-4': {
name: 'Luxury Premium',
bg: 'linear-gradient(135deg, #1a1a2e 0%, #2c2c54 100%)',
accent: '#ffd700',
text: '#ffffff',
secondary: '#3d3d5c'
},
'theme-5': {
name: 'Friendly Local',
bg: 'linear-gradient(135deg, #fff5f5 0%, #fff 100%)',
accent: '#e74c3c',
text: '#2c3e50',
secondary: '#ffeaa7'
}
};
function selectTheme(el) {
// existing code
document.querySelectorAll('.theme-option').forEach(t => t.classList.remove('selected'));
el.classList.add('selected');
selectedTheme = el.dataset.theme;
previewSite();
}
function updateImagePreview() {
const service = document.getElementById('serviceType').value;
const images = stockImages[service];
const container = document.getElementById('imagePreview');
let html = `
`;
images.services.slice(0, 2).forEach(img => {
html += `
`;
});
container.innerHTML = html;
}
function getServiceOptions(service) {
const options = {
'plumbing': ['Emergency Repairs', 'Drain Cleaning', 'Water Heater Install', 'Pipe Replacement', 'Bathroom Remodel'],
'hvac': ['AC Repair', 'Heating Service', 'AC Installation', 'Maintenance', 'Indoor Air Quality'],
'roofing': ['Roof Repair', 'Roof Replacement', 'Storm Damage', 'Gutter Installation', 'Inspection'],
'electrical': ['Electrical Repairs', 'Panel Upgrades', 'Lighting Install', 'Safety Inspections', 'EV Chargers'],
'pool': ['Pool Cleaning', 'Pool Maintenance', 'Pool Repairs', 'Pool Opening/Closing', 'Chemical Services'],
'painting': ['Interior Painting', 'Exterior Painting', 'Cabinet Refinishing', 'Deck Staining', 'Commercial'],
'flooring': ['Hardwood Flooring', 'Tile Installation', 'Carpet Install', 'Vinyl/LVP', 'Floor Repair'],
'appliance': ['Refrigerator Repair', 'Washer/Dryer Repair', 'Dishwasher Repair', 'Oven/Range Repair', 'AC Appliance Repair'],
'pest': ['Termite Control', 'Bed Bug Treatment', 'Rodent Control', 'Mosquito Treatment', 'General Pest Control'],
'siding': ['Vinyl Siding', 'Fiber Cement Siding', 'Siding Repair', 'Siding Replacement', 'Siding Painting'],
'masonry': ['Brick Repair', 'Concrete Work', 'Patio Install', 'Retaining Walls', 'Chimney Repair'],
'landscaping': ['Lawn Maintenance', 'Tree Service', 'Landscape Design', 'Irrigation', 'Outdoor Lighting'],
'handyman': ['General Repairs', 'Furniture Assembly', 'TV Mounting', 'Door/Window Repair', 'Minor Plumbing'],
'cleaning': ['House Cleaning', 'Deep Cleaning', 'Move In/Out Cleaning', 'Office Cleaning', 'Carpet Cleaning'],
'carpet': ['Carpet Cleaning', 'Steam Cleaning', 'Stain Removal', 'Carpet Repair', 'Upholstery Cleaning']
};
return options[service] || options['plumbing'];
}
// Slot-by-slot image upload
function generateSlotUploads() {
const serviceType = document.getElementById('serviceType').value;
let services = getServiceOptions(serviceType) || [];
const container = document.getElementById('slotUploads');
// Slots: hero + 5 services + team + projects
const slots = [
{ id: 'hero', label: 'Hero Image (main banner)' },
{ id: 'service1', label: 'Service 1: ' + services[0] },
{ id: 'service2', label: 'Service 2: ' + services[1] },
{ id: 'service3', label: 'Service 3: ' + services[2] },
{ id: 'service4', label: 'Service 4: ' + services[3] },
{ id: 'service5', label: 'Service 5: ' + (services[4] || '') },
{ id: 'team1', label: 'Team Member 1 (photo)' },
{ id: 'team2', label: 'Team Member 2 (photo)' },
{ id: 'project1', label: 'Completed Project 1 (photo)' },
{ id: 'project2', label: 'Completed Project 2 (photo)' },
{ id: 'project3', label: 'Completed Project 3 (photo)' }
];
let html = '';
slots.forEach(slot => {
html += `
`;
});
container.innerHTML = html;
}
function handleSlotImage(input, slotId) {
const file = input.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
const preview = document.getElementById('preview_' + slotId);
preview.innerHTML = '
✅ ' + file.name;
preview.style.color = '#27ae60';
// Store the image data
if (!window.customSlotImages) window.customSlotImages = {};
window.customSlotImages[slotId] = e.target.result;
const debugBox = document.getElementById('debugInfo');
if (debugBox) {
debugBox.innerHTML = 'Debug: customSlotImages has ' + Object.keys(window.customSlotImages).length + ' images';
}
};
reader.readAsDataURL(file);
}
function previewSite() {
const data = getFormData();
const theme = themes[selectedTheme];
const services = getServiceOptions(data.serviceType);
let images = JSON.parse(JSON.stringify(stockImages[data.serviceType]));
// Override with custom uploaded images
if (window.customSlotImages) {
if (window.customSlotImages['hero']) images.hero = window.customSlotImages['hero'];
if (window.customSlotImages['service1']) images.services[0] = window.customSlotImages['service1'];
if (window.customSlotImages['service2']) images.services[1] = window.customSlotImages['service2'];
if (window.customSlotImages['service3']) images.services[2] = window.customSlotImages['service3'];
if (window.customSlotImages['service4']) images.services[3] = window.customSlotImages['service4'];
if (window.customSlotImages['service5']) images.services[4] = window.customSlotImages['service5'];
// Team images
if (!images.team) images.team = [];
if (window.customSlotImages['team1']) images.team[0] = window.customSlotImages['team1'];
if (window.customSlotImages['team2']) images.team[1] = window.customSlotImages['team2'];
// Project images
if (!images.projects) images.projects = [];
if (window.customSlotImages['project1']) images.projects[0] = window.customSlotImages['project1'];
if (window.customSlotImages['project2']) images.projects[1] = window.customSlotImages['project2'];
if (window.customSlotImages['project3']) images.projects[2] = window.customSlotImages['project3'];
}
// Generate services with images
let servicesHTML = services.map((s, i) => `
${['🔧','⚡','🛠️','✅','🏠'][i]}
${s}
`).join('');
const heroOverlay = theme.name === 'Clean Professional' || theme.name === 'Vibrant Service' || theme.name === 'Friendly Local'
? 'rgba(255,255,255,0.85)'
: 'rgba(0,0,0,0.5)';
const html = `
${data.businessName || 'Your Business'} | ${data.serviceType.charAt(0).toUpperCase() + data.serviceType.slice(1)} in ${data.location}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: '${data.headingFont}', system-ui, sans-serif;
background: ${theme.bg};
color: ${theme.text};
line-height: 1.6;
}
header {
background: rgba(0,0,0,0.2);
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo { font-size: 1.5rem; font-weight: 700; color: ${theme.accent}; }
.hero {
padding: 5rem 2rem;
text-align: center;
background: linear-gradient(${heroOverlay}, ${heroOverlay}), url(${images.hero});
background-size: cover;
background-position: center;
}
.hero h1 {
font-size: 3rem;
margin-bottom: 1rem;
}
.hero p {
font-size: 1.3rem;
opacity: 0.9;
}
.services {
max-width: 1200px;
margin: 4rem auto;
padding: 0 2rem;
}
.services h2 {
text-align: center;
margin-bottom: 2rem;
font-size: 2rem;
color: ${theme.accent};
}
.service-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1.5rem;
}
.cta {
background: ${theme.accent};
color: white;
padding: 4rem 2rem;
text-align: center;
}
.cta h2 { margin-bottom: 1rem; }
.phone {
font-size: 2.5rem;
font-weight: 700;
}
.contact {
max-width: 1000px;
margin: 4rem auto;
padding: 3rem 2rem;
background: #f8f9fa;
color: #1a1a2e;
}
.contact h2 {
text-align: center;
margin-bottom: 1rem;
font-size: 2rem;
}
.form-container {
background: white;
border-radius: 12px;
padding: 2rem;
margin: 2rem auto;
max-width: 500px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.form-container h3 {
margin-bottom: 1rem;
color: #ff6b35;
}
.form-container input,
.form-container select,
.form-container textarea {
width: 100%;
padding: 0.8rem;
margin-bottom: 1rem;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 1rem;
font-family: inherit;
}
.form-container button {
background: #ff6b35;
color: white;
border: none;
padding: 1rem 2rem;
border-radius: 6px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
width: 100%;
}
.form-container button:hover {
background: #e55a2b;
}
.contact-info {
text-align: center;
margin-top: 2rem;
padding-top: 2rem;
border-top: 1px solid #ddd;
}
.contact-info p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
footer {
background: rgba(0,0,0,0.3);
padding: 2rem;
text-align: center;
opacity: 0.7;
}
Professional ${data.serviceType.charAt(0).toUpperCase() + data.serviceType.slice(1)} Services in ${data.location || 'Your City'}
Licensed, Insured, and Ready to Serve You
Our Services
${servicesHTML}
Our Team

Team Member 1

Team Member 2
Completed Projects

Project 1

Project 2

Project 3
Ready to Get Started?
📞 ${data.phone || '(555) 000-0000'}
`;
const iframe = document.getElementById('previewIframe');
iframe.srcdoc = html;
}
function getFormData() {
return {
businessName: document.getElementById('businessName').value,
serviceType: document.getElementById('serviceType').value,
location: document.getElementById('location').value,
phone: document.getElementById('phone').value,
email: document.getElementById('email').value,
theme: selectedTheme,
primaryColor: document.getElementById('primaryColor').value,
headingFont: document.getElementById('headingFont').value
};
}
// Load client data from URL code
let currentBuildId = null;
// Global helper: hide business fields for demo mode
function hideBusinessFields() {
console.log('hideBusinessFields called');
alert('hideBusinessFields CALLED!');
const hideIds = ['businessName', 'serviceType', 'location', 'phone', 'email'];
hideIds.forEach(id => {
const input = document.getElementById(id);
if (input) {
input.style.display = 'none';
const group = input.closest('.form-group');
if (group) {
group.style.display = 'none';
console.log('Hid: ' + id);
}
}
});
const h2 = document.querySelector('.controls h2');
if (h2) h2.textContent = '🖼️ Customize Theme & Add Images';
const actions = document.querySelector('.controls .actions');
if (actions) actions.style.display = 'flex';
}
async function loadClientFromCode() {
// Load client data on page load if code param present
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const statusDiv = document.getElementById('debugStatus');
statusDiv.textContent = 'loadClientFromCode: ' + code;
statusDiv.textContent = 'Code found: ' + code + ' - querying Airtable...';
// Ensure business fields are hidden for demo codes
hideBusinessFields();
// Detect service type from code if no Airtable record
const codeServiceMap = {
'plumbing': 'plumbing', 'plumber': 'plumbing',
'hvac': 'hvac', 'ac': 'hvac', 'heating': 'hvac', 'cool': 'hvac',
'roofing': 'roofing', 'roof': 'roofing',
'electrical': 'electrical', 'electric': 'electrical',
'pool': 'pool',
'painting': 'painting', 'paint': 'painting',
'pest': 'pest', 'pestcontrol': 'pest',
'cleaning': 'cleaning', 'clean': 'cleaning',
'landscaping': 'landscaping', 'landscape': 'landscaping'
};
const codeLower = code.toLowerCase();
let detectedService = '';
const keys = Object.keys(codeServiceMap);
for (let i = 0; i < keys.length; i++) {
if (codeLower.indexOf(keys[i]) !== -1) {
detectedService = codeServiceMap[keys[i]];
break;
}
}
// Try to find client by Build ID (code)
try {
const resp = await fetch('/api/airtable?table=Website%20Builds?filterByFormula=({Build%20ID}=\'' + code + '\')', {
headers: { 'Content-Type': 'application/json' }
});
const data = await resp.json();
if (data.records && data.records.length > 0) {
const fields = data.records[0].fields;
currentBuildId = fields['Build ID'];
// Pre-fill form
if (fields['Business Name']) document.getElementById('businessName').value = fields['Business Name'];
if (fields['Service Type']) document.getElementById('serviceType').value = fields['Service Type'];
if (fields['Location']) document.getElementById('location').value = fields['Location'];
if (fields['Phone']) document.getElementById('phone').value = fields['Phone'];
if (fields['Email']) document.getElementById('email').value = fields['Email'];
if (fields['Theme']) selectedTheme = fields['Theme'];
if (fields['Primary Color']) document.getElementById('primaryColor').value = fields['Primary Color'];
if (fields['Heading Font']) document.getElementById('headingFont').value = fields['Heading Font'];
// Update image slots for this service type
generateSlotUploads();
// Load existing images from Airtable
try {
const imgResp = await fetch('/api/airtable?table=Website%20Images?filterByFormula=({Build%20ID}=\'' + (currentBuildId || code) + '\')', {
headers: { 'Content-Type': 'application/json' }
});
const imgData = await imgResp.json();
if (imgData.records && imgData.records.length > 0) {
if (!window.customSlotImages) window.customSlotImages = {};
const slotReverseMap = { 'hero': 'hero', 'service1': 'service1', 'service2': 'service2', 'service3': 'service3', 'service4': 'service4', 'service5': 'service5', 'about1': 'team1', 'about2': 'team2', 'job1': 'project1', 'job2': 'project2', 'job3': 'project3' };
for (let i = 0; i < imgData.records.length; i++) {
const rec = imgData.records[i];
const imgType = rec.fields['Image Type'];
const desc = rec.fields['Description'];
const slot = slotReverseMap[imgType] || imgType;
if (desc && desc.startsWith('data:')) {
window.customSlotImages[slot] = desc;
// Update preview
const preview = document.getElementById('preview_' + slot);
if (preview) {
preview.innerHTML = '
✅ Saved';
preview.style.color = '#27ae60';
}
}
}
}
} catch(e) {
console.log('Error loading existing images:', e);
}
// Hide form fields, show only theme/font and image upload
// Hide by finding the parent of specific input IDs
// hide handled by hideBusinessFields
hideBusinessFields();
return true;
}
} catch(e) {
console.log('No client found for code:', code);
}
// If no Airtable record but detected service from code
if (detectedService) {
document.getElementById('serviceType').value = detectedService;
document.getElementById('businessName').value = 'Demo ' + detectedService.charAt(0).toUpperCase() + detectedService.slice(1);
generateSlotUploads();
// Hide form fields, show only theme/font and image upload
const hideIds = ['businessName', 'serviceType', 'location', 'phone', 'email'];
hideIds.forEach(id => {
const input = document.getElementById(id);
if (input && input.parentElement.classList.contains('form-group')) {
input.parentElement.style.display = 'none';
}
});
document.querySelector('.controls h2').textContent = '🖼️ Customize Theme & Add Images';
// Show actions for image upload
document.querySelector('.controls .actions').style.display = 'flex';
return true;
}
return false;
}
async function submitBuild() {
const data = getFormData();
const params = new URLSearchParams(window.location.search);
const urlCode = params.get('code');
const buildId = currentBuildId || urlCode || 'BUILD-' + Date.now();
// Save to Airtable
try {
let response;
if (currentBuildId) {
// Update existing build
response = { ok: true };
} else {
response = await fetch('/api/airtable?table=Website%20Builds', {
method: 'POST',
headers: {
'Authorization: Bearer (use proxy),
'Content-Type': 'application/json'
},
body: JSON.stringify({
fields: {
'Build ID': buildId,
'Business Name': data.businessName,
'Service Type': data.serviceType,
'Location': data.location,
'Phone': data.phone,
'Email': data.email,
'Theme': data.theme,
'Primary Color': data.primaryColor,
'Heading Font': data.headingFont,
'Status': 'Pending'
}
})
});
}
// Save custom images to Airtable as base64 text
let imagesSaved = 0;
const debugInfo = document.getElementById('debugInfo') || document.createElement('div');
debugInfo.id = 'debugInfo';
debugInfo.style.cssText = 'position:fixed;bottom:10px;left:10px;background:#fff;color:#000;padding:10px;z-index:9999;font-size:12px;max-width:300px;word-break:break-all;';
document.body.appendChild(debugInfo);
debugInfo.innerHTML = 'Debug: customSlotImages has ' + (window.customSlotImages ? Object.keys(window.customSlotImages).length : 0) + ' images';
if (window.customSlotImages) {
const slotMapping = {
'hero': 'hero',
'service1': 'service1', 'service2': 'service2', 'service3': 'service3',
'service4': 'service4', 'service5': 'service5',
'team1': 'about1', 'team2': 'about2',
'project1': 'job1', 'project2': 'job2', 'project3': 'job3'
};
const slots = ['hero', 'service1', 'service2', 'service3', 'service4', 'service5', 'team1', 'team2', 'project1', 'project2', 'project3'];
for (let i = 0; i < slots.length; i++) {
const slot = slots[i];
if (window.customSlotImages[slot]) {
try {
const airtableSlot = slotMapping[slot] || slot;
// Save base64 image data to Airtable
const imgResp = await fetch('/api/airtable?table=Website%20Images', {
method: 'POST',
headers: {
'Authorization: Bearer (use proxy),
'Content-Type': 'application/json'
},
body: JSON.stringify({
fields: {
'Build ID': buildId,
'Image Type': airtableSlot,
'Description': window.customSlotImages[slot].substring(0, 1000), // truncate for debug
'Status': 'Submitted'
}
})
});
const imgText = await imgResp.text();
alert('Image save response: ' + imgResp.status + ' - ' + imgText.substring(0, 100));
if (imgResp.ok) imagesSaved++;
} catch(e) {
console.log('Image save error:', e);
}
}
}
}
alert('Saved ' + imagesSaved + ' images to Airtable!');
if (response.ok) {
document.getElementById('buildId').textContent = 'Build ID: ' + buildId;
document.getElementById('overlay').classList.add('show');
document.getElementById('successMessage').classList.add('show');
} else {
alert('Error saving. Please try again.');
}
} catch (e) {
// Fallback: show success anyway for demo
document.getElementById('buildId').textContent = 'Build ID: ' + buildId + ' (Demo Mode)';
document.getElementById('overlay').classList.add('show');
document.getElementById('successMessage').classList.add('show');
}
}
function closeSuccess() {
document.getElementById('overlay').classList.remove('show');
document.getElementById('successMessage').classList.remove('show');
}
// Initialize - run immediately (script is at end of body, DOM ready)
(function() {
const statusDiv = document.getElementById('debugStatus');
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
statusDiv.textContent = code ? 'Code: ' + code : 'No code';
if (code) {
// Hide business fields FIRST, then load client
hideBusinessFields();
loadClientFromCode();
}
updateImagePreview();
generateSlotUploads();
})();
// Load custom images from localStorage (from stock-image-manager)
function loadCustomImages() {
const serviceType = document.getElementById('serviceType').value;
const slots = ['hero', 'service1', 'service2', 'service3', 'service4', 'service5', 'team1', 'team2', 'project1', 'project2', 'project3'];
slots.forEach(slot => {
const key = `custom_${serviceType}_${slot}`;
const customUrl = localStorage.getItem(key);
if (customUrl) {
// Update preview if exists
const preview = document.querySelector(`[data-slot="${slot}"]`);
if (preview) {
preview.src = customUrl;
}
}
});
}
// Load custom images when service type changes
document.getElementById('serviceType').addEventListener('change', loadCustomImages);
loadCustomImages(); // Also run on init
// Custom images handling
const customImages = [];
function handleCustomImages(input) {
const list = document.getElementById('customImagesList');
list.innerHTML = '';
for (const file of input.files) {
const reader = new FileReader();
reader.onload = function(e) {
const div = document.createElement('div');
div.style.cssText = 'display: inline-block; margin: 5px; padding: 5px; background: rgba(39,174,96,0.2); border-radius: 4px; font-size: 0.75rem;';
div.innerHTML = '✅ ' + file.name;
list.appendChild(div);
};
reader.readAsDataURL(file);
}
}
Theme Previews
Click on a theme to select it and close this preview.
Bold Modern
High contrast, professional, bold typography
Clean Pro
Clean white, corporate, trustworthy
Vibrant
Energetic, colorful, eye-catching
Luxury
Premium, gold accents, elegant
Friendly
Warm, welcoming, local business feel
function openThemePreview() {
document.getElementById('themePreviewModal').style.display = 'block';
document.body.style.overflow = 'hidden';
}
function closeThemePreview() {
document.getElementById('themePreviewModal').style.display = 'none';
document.body.style.overflow = 'auto';
}
function selectThemeAndClose(theme) {
selectThemeById(theme);
closeThemePreview();
}
function selectThemeById(theme) {
document.querySelectorAll('.theme-option').forEach(t => t.classList.remove('selected'));
document.querySelector('[data-theme="' + theme + '"]').classList.add('selected');
selectedTheme = theme;
}